import AppNode from "../app_node";
import { EleInput, EleDiv } from "../data_ext";
import { RegClass } from "../serialize";
import Utils from "../utils";
import PrefabStr from "./color_picker.prefab.html?raw"

@RegClass("ColorPicker")
export default class ColorPicker extends AppNode {
    ebHex: EleInput = null;
    hueHandle: EleDiv = null;
    hue: EleDiv = null;
    hueValue = 0;

    sl: EleDiv = null;
    slHandle: EleDiv = null;
    sValue = 0; //X，饱和度
    lValue = 0; //Y，亮度
    onLoad(): void {
        this.hue.onmousedown = this.onMouseDownHue.bind(this);
        this.hue.onmousemove = this.onMouseMoveHue.bind(this);
        this.hue.onmouseup = this.onMouseUpHue.bind(this);
        this.sl.onmousedown = this.onMouseDownSl.bind(this);
        this.sl.onmousemove = this.onMouseMoveSl.bind(this);
        this.sl.onmouseup = this.onMouseUpSl.bind(this);

        this.refresh();
    }
    touchingHue = false;
    updateHue(x) {
        this.hueValue = Math.max(0, Math.min(1, x / this.hue.clientWidth));
        console.log(this.hueValue);
        this.refresh();
        this.subject.emit("changed", [this.hueValue, this.sValue, this.lValue]);
    }
    onMouseDownHue(evt: MouseEvent) {
        this.touchingHue = true;
        this.updateHue(evt.offsetX);
    }
    onMouseMoveHue(evt: MouseEvent) {
        if (this.touchingHue) {
            this.updateHue(evt.offsetX);
        }
    }
    onMouseUpHue(evt: MouseEvent) {
        if (this.touchingHue) {
            this.touchingHue = false;
        }
    }

    touchingSl = false;
    yValue = 0;
    updateSl(x, y) {
        this.sValue = Math.max(0, Math.min(1, x / this.sl.clientWidth));
        this.yValue = Math.max(0, Math.min(1, y / this.sl.clientHeight));
        this.lValue = 0.5 - 0.5 * this.sValue + (0.5 - 0.5 * this.yValue);

        this.refresh();
        this.subject.emit("changed", [this.hueValue, this.sValue, this.lValue]);
    }
    onMouseDownSl(evt: MouseEvent) {
        this.touchingSl = true;
        this.updateSl(evt.offsetX, evt.offsetY);
    }
    onMouseMoveSl(evt: MouseEvent) {
        if (this.touchingSl) {
            this.updateSl(evt.offsetX, evt.offsetY);
        }
    }
    onMouseUpSl(evt: MouseEvent) {
        if (this.touchingSl) {
            this.touchingSl = false;
        }
    }

    refresh() {
        this.sl.style.backgroundColor = `hsl(${Math.floor(this.hueValue * 360)}, 100%, 50%)`;
        this.hueHandle.style.left = `calc(${this.hueValue * 100}% - 5px)`;
        this.slHandle.style.left = `calc(${this.sValue * 100}% - 5px)`;
        this.slHandle.style.top = `calc(${this.yValue * 100}% - 5px)`;
        let [r, g, b] = Utils.HSL2RGB(this.hueValue * 360, this.sValue, this.lValue);
        let hex = "#" + this._writeHex(r, 2) + this._writeHex(g, 2) + this._writeHex(b, 2);
        this.ebHex.value = hex;
    }

    setHex(hex: string) {
        if ("#" === hex[0]) {
            hex = hex.substring(1);
        }
        let colorDigit = 1;
        // f f f f 
        if (hex.length === 3 || hex.length === 4) {
            colorDigit = 1;
        }
        // ff ff ff ff
        else if (hex.length === 6 || hex.length === 8) {
            colorDigit = 2;
        }
        let seek = 0;
        let r = this._readHex(hex.substring(seek, seek + colorDigit));
        seek += colorDigit;
        let g = this._readHex(hex.substring(seek, seek + colorDigit));
        seek += colorDigit;
        let b = this._readHex(hex.substring(seek, seek + colorDigit));

        let [h, s, l] = Utils.RGB2HSL(r, g, b);

        this.hueValue = h / 360;
        this.sValue = s;
        this.lValue = l;

        this.refresh();
        this.subject.emit("changed", [this.hueValue, this.sValue, this.lValue]);
    }

    onEditHex() {
        this.setHex(this.ebHex.value);
    }


    protected _writeHex(int: number, digit = 2) {
        let str = int.toString(16);
        if (str.length !== digit) {
            str = str.substring(str.length - digit, str.length);
        }
        return str;
    }
    protected _readHex(str: string) {
        return parseInt(str, 16);
    }
    
    static get __BindPrefab__(): string {
        return PrefabStr;
    }
};